if not delta then

dofile (ScriptsRootPath .. "lib\\lib.lua")
dofile (ScriptsRootPath .. "lib\\index.lua")
	
delta = {
	data = {},
	OnM1 = {},
	average_period = 10,
	signal_parameter = 15
}

function delta:add(trade, table_index)
	if trade and type(trade) == "table"
		and trade.sec_code
		and self.data[trade.sec_code]
		and self:IsNewTrade(trade.sec_code, table_index)
	then
		local min = int(trade.datetime.hour * 60 + trade.datetime.min)
		local index = #self.data[trade.sec_code]
		local tm = tostring(min)
		local dd = self.data[trade.sec_code][tm]
		
		if not dd then
			dd = self:CalculateTotal(self:LinkData({
				sec_code = trade.sec_code,
				trades = 0,
				volume = 0,
				value = 0,
				time = string.format("%02d%02d", trade.datetime.hour, trade.datetime.min),
				min = min
			}))
			if index > 0 then
				local last = self.data[trade.sec_code][ self.data[trade.sec_code][index] ]
				self:CalculateSignal(self:CalculateAverage(last))
				
				if not self.data[trade.sec_code].finished then
					self.data[trade.sec_code].finished = index
				end
				
				for i, v in ipairs(self.OnM1) do
					v(last)
				end
			end
		end
		
		if dd then
			if bit.test(trade.flags, 0) then	-- short
			
				dd.trades = dd.trades - 1
				dd.total_trades = dd.total_trades - 1
				dd.volume = dd.volume - trade.qty
				dd.total_volume = dd.total_volume - trade.qty
				dd.value = dd.value - trade.value
				dd.total_value = dd.total_value - trade.value
				
			elseif bit.test(trade.flags, 1) then	-- long
			
				dd.trades = dd.trades + 1
				dd.total_trades = dd.total_trades + 1
				dd.volume = dd.volume + trade.qty
				dd.total_volume = dd.total_volume + trade.qty
				dd.value = dd.value + trade.value
				dd.total_value = dd.total_value + trade.value
				
			end
		end
		
		return dd
	end
end

function delta:IsNewTrade(sec_code, table_index)
	if sec_code
		and self.data[sec_code]
		and table_index
		and self.data[sec_code].table_index
		and self.data[sec_code].table_index <= table_index
	then
		self.data[sec_code].table_index = table_index + 1
		return true
	end
end

function delta:get(sec_code, datetime, interval)
	local dd
	
	if sec_code and datetime and self.data[sec_code] and interval > 0 then
		local tm = datetime.hour * 60 + datetime.min
		local d
		
		for i = 0, interval - 1 do
			d = self.data[sec_code][tostring(int(tm + i))]
			if d then
				if dd then
					dd.trades = dd.trades + d.trades
					dd.total_trades = d.total_trades
					dd.volume = dd.volume + d.volume
					dd.total_volume = d.total_volume
					dd.value = dd.value + d.value
					dd.total_value = d.total_value
					if d.signal_long and (not dd.signal_long or dd.signal_long < d.signal_long) then
						--dd.signal_long = (dd.signal_long or 0) + d.signal_long
						dd.signal_long = d.signal_long
					end
					if d.signal_short and (not dd.signal_short or dd.signal_short > d.signal_short) then
						--dd.signal_short = (dd.signal_short or 0) - d.signal_short
						dd.signal_short = d.signal_short
					end
				else
					dd = lib:clone(d)
				end
			end
		end
		if dd and (not dd.average_trades or interval > 1) then
			self:CalculateAverage(dd, interval)
		end
		--self:CalculateSignal(dd)
	end
	
	return dd
end

function delta:GetSignalCount(sec_code)
	local n = 0
	if sec_code and self.data[sec_code] then
		for i = 1, #self.data[sec_code] do
			if self.data[sec_code][ self.data[sec_code][i] ].signal_long
				or self.data[sec_code][ self.data[sec_code][i] ].signal_short
			then
				n = n + 1
			end
		end
	end
	return n
end

function delta:CalculateTotal(dd)
	if type(dd) == "table" and dd.sec_code and self.data[dd.sec_code] and dd.index then
		dd.total_trades = dd.trades
		dd.total_volume = dd.volume
		dd.total_value = dd.value
		if dd.index > 1 then
			dd.total_trades = dd.total_trades + self.data[dd.sec_code][ self.data[dd.sec_code][dd.index - 1] ].total_trades
			dd.total_volume = dd.total_volume + self.data[dd.sec_code][ self.data[dd.sec_code][dd.index - 1] ].total_volume
			dd.total_value = dd.total_value + self.data[dd.sec_code][ self.data[dd.sec_code][dd.index - 1] ].total_value
		end
		
		return dd
	end
end

function delta:CalculateAverage(dd, interval)
	interval = interval or 1
	if type(dd) == "table" and dd.sec_code and self.data[dd.sec_code] and dd.index and interval > 0 then
		dd.average_trades = 0
		dd.average_volume = 0
		dd.average_value = 0
		if dd.index > 1 then
			for i = dd.index - interval * self.average_period, dd.index - 1 do
				if i > 0 then
					dd.average_trades = dd.average_trades
						+ math.abs(self.data[dd.sec_code][ self.data[dd.sec_code][i] ].trades)
					dd.average_volume = dd.average_volume
						+ math.abs(self.data[dd.sec_code][ self.data[dd.sec_code][i] ].volume)
					dd.average_value = dd.average_value
						+ math.abs(self.data[dd.sec_code][ self.data[dd.sec_code][i] ].value)
				end
			end
			dd.average_trades = dd.average_trades / math.min((dd.index - 1) / interval, self.average_period)
			dd.average_volume = dd.average_volume / math.min((dd.index - 1) / interval, self.average_period)
			dd.average_value = dd.average_value / math.min((dd.index - 1) / interval, self.average_period)
		end
		if dd.average_trades == 0 then
			--dd.average_trades = 1 / 0
			dd.average_trades = math.abs(dd.trades)
		end
		if dd.average_volume == 0 then
			--dd.average_volume = 1 / 0
			dd.average_volume = math.abs(dd.volume)
		end
		if dd.average_value == 0 then
			--dd.average_value = 1 / 0
			dd.average_value = math.abs(dd.value)
		end
		if dd.average_trades == 0 then
			dd.average_trades = 1
		end
		if dd.average_volume == 0 then
			dd.average_volume = 1
		end
		if dd.average_value == 0 then
			dd.average_value = 1
		end
	
		return dd
	end
end

function delta:CalculateSignal(dd)
	if type(dd) == "table" then
		dd.signal_long = nil
		dd.signal_short = nil
		
		if dd.min < 1120	-- regular section only
		then
			-- Trade number splash
			if dd.index > self.average_period -- * 2
				--and dd.average_volume * 2 > math.abs(dd.volume)
			then
				if dd.trades / dd.average_trades >= self.signal_parameter then
					dd.signal_long = 0 + dd.trades / dd.average_trades / 100
					--dd.signal_long = dd.min
				elseif dd.trades / dd.average_trades <= -self.signal_parameter
					and lib:CanShort(dd.sec_code)
				then
					dd.signal_short = - 0 + dd.trades / dd.average_trades / 100
					--dd.signal_short = - dd.min
				end
				--dd.signal_long = 0
			end
			--[[
			-- Volume delta inversion
			if dd.index > 7
				and not dd.signal_long
				and not dd.signal_short
				and dd.total_volume
			then
				local d = self.data[dd.sec_code][ self.data[dd.sec_code][dd.index - 1] ]
				if d.total_volume then
					if dd.total_volume > 0 and d.total_volume < 0 then
						dd.signal_long = 1
					elseif dd.total_volume < 0 and d.total_volume > 0 then
						dd.signal_short = -1
					end
				--else
					--message("d " .. lib:toline(d))
					--message("dd " .. lib:toline(dd))
				end
				if dd.signal_long
					or dd.signal_short
				then
					local f
					for i = dd.index - 2, 2, -1 do
						d = self.data[dd.sec_code][ self.data[dd.sec_code][i] ]
						if not d.total_volume
							or dd.signal_short and (dd.volume > d.volume)-- or d.total_volume < 0)
							or dd.signal_long and (dd.volume < d.volume)-- or d.total_volume > 0)
						then
							f = true
							break
						end
					end
					if f then
						dd.signal_long = nil
						dd.signal_short = nil
					end
				end
			end
			--]]
		end
	
		return dd
	end
end

function delta:LinkData(dd)
	if type(dd) == "table" and dd.sec_code and self.data[dd.sec_code] and dd.min then
		local index = #self.data[dd.sec_code]
		if index == 0 or self.data[dd.sec_code][ self.data[dd.sec_code][index] ].min < dd.min then
			table.sinsert(self.data[dd.sec_code], tostring(dd.min))
			dd.index = #self.data[dd.sec_code]
			self.data[dd.sec_code][tostring(dd.min)] = dd
			
			return dd
		end
	end
end

function delta:line2data(line, sec_code)
	if line and sec_code then
		local d = split(line, "\t")
		if #d >= 4 then
			return {
				sec_code = sec_code,
				time = d[1],
				min = int(string.sub(d[1], 1, 2)) * 60 + int(string.sub(d[1], 3, 4)),
				trades = int(d[2]),
				volume = int(d[3]),
				value = tonumber(d[4])
			}
		end
	end
end

function delta:load(sec_code, date)
	self.data[sec_code] = {date = lib:FormatDate(date)}
	
	--message("delta:load " .. sec_code .. " " .. self.data[sec_code].date)
	
	local file = lib.path.delta .. self.data[sec_code].date .. "." .. sec_code
	local data, dd
	
	local hf = io.open(file, "r")
	if hf then
		data = hf:read("*a")
		hf:close()
		
		if data then
			for v in string.gmatch(data, "([^\n]+)\n") do
				dd = self:LinkData(self:line2data(v, sec_code))
				if dd then
					dd.loaded = true
					self:CalculateSignal(self:CalculateAverage(self:CalculateTotal(dd)))
				end
			end
		end
	end
	
	if self.data[sec_code].date == lib:FormatDate() then		-- today
		self.data[sec_code].table_index = 0
		if dd then
			data = index:GetMin(dd.min)
			if data then
				self.data[sec_code].table_index = data.last + 1
			end
		end
	--else														-- history
	end
	self.table_index = nil
	
	--message("delta:load " .. lib:toline(self.data[sec_code][ self.data[sec_code][ #self.data[sec_code] ] ]))
	
	return self.data[sec_code]
end

function delta:update(delay)
	local tm
	if delay then
		tm = lib:GetTime()
	end
	
	if not self.table_index then
		for k, v in pairs(self.data) do
			if type(v) == "table" then
				if v.table_index then
					if self.table_index then
						self.table_index = math.min(self.table_index, v.table_index)
					else
						self.table_index = v.table_index
					end
				end
			end
		end
	end
	
	if self.table_index then
		local trade
		while self.table_index < getNumberOf("all_trades") do
			trade = getItem("all_trades", self.table_index)
			if trade then
				self:add(trade, self.table_index)
			else
				return
			end
			self.table_index = self.table_index + 1
			if self.table_index % 1000 == 0 and tm and lib:IsDelay(tm, delay) then
				return
			end
		end
		
		return true
	end
end

if not Settings then	-- not an indicator

	dofile (ScriptsRootPath .. "processor\\processor.lua")
	dofile (ScriptsRootPath .. "processor\\saver.lua")
	
	delta.saver = {}

	function delta:save(sec_code, date)
		local updated
		
		if type(sec_code) == "string" then
			local sid = "delta." .. sec_code
			if self.saver[sec_code] ~= (date or lib:FormatDate()) then
				local file = lib.path.delta .. (date or lib:FormatDate()) .. "." .. sec_code
				processor:InitSharedSaver(sid, file)
				processor:save(sid, "")
				if not date and self.saver[sec_code] then
					self:load(sec_code)
				end
				self.saver[sec_code] = (date or lib:FormatDate())
			end
			
			local dd, signal
			if self.data[sec_code].finished then
				for i = self.data[sec_code].finished, #self.data[sec_code] - 1 do
					dd = self.data[sec_code][ self.data[sec_code][i] ]
					if not dd.loaded then
						if dd.signal_long then
							signal = "BUY"
						elseif dd.signal_short then
							signal = "SELL"
						else
							signal = ""
						end
						
						processor:save(sid, string.format("%s\t%d\t%d\t%.2f\t\t%d\t%d\t%.2f\t\t%.2f\t%.2f\t%.2f\t\t%s",
							dd.time,
							
							dd.trades,
							dd.volume,
							dd.value,
							
							dd.total_trades,
							dd.total_volume,
							dd.total_value,
							
							dd.average_trades,
							dd.average_volume,
							dd.average_value,
							
							signal
						))
					end
				end
				self.data[sec_code].finished = nil
			end
		else
			if self.date ~= lib:FormatDate() then
				if self.date then
					self.table_index = 0
				end
				self.date = lib:FormatDate()
			else
				updated = self:update(sec_code)
			end
			for k in pairs(self.data) do
				self:save(k)
			end
		end
		
		return updated
	end
	
end	-- indicator exclude


end -- of file


